<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <script>
        let { log } = console;
        // //////////////////////////////////////////////////////////////
        // //Object.assign 模拟实现(实现原理) object 实例拷贝
        // //////////////////////////////////////////////////////////////


        // if (typeof Object.assign2 != 'function') {
        //     // Attention 1
        //     Object.defineProperty(Object, "assign2", {
        //         value: function (target) {
        //             'use strict';
        //             if (target == null) { // Attention 2
        //                 throw new TypeError('Cannot convert undefined or null to object');
        //             }

        //             // Attention 3
        //             let to = Object(target);

        //             for (let index = 1; index < arguments.length; index++) {
        //                 let orginSource = arguments[index];

        //                 if (orginSource != null) {  // Attention 2
        //                     // Attention 4

        //                     // Reflect.ownKeys返回一个数组，包含对象自身的（不含继承的）所有键名，不管键名是 Symbol 或字符串，也不管是否可枚举。
        //                     // console.log(Reflect.ownKeys(orginSource));
        //                     // console.log(orginSource.hasOwnProperty("prop1"));

        //                     for (let key of Reflect.ownKeys(orginSource)) {

        //                         // 真正的拷贝 注意这是第一层自身属性深度拷贝，第二层之后是浅拷贝！
        //                         Reflect.defineProperty(to,key,Reflect.getOwnPropertyDescriptor(orginSource,key));

        //                         // to[key] = orginSource[key];

        //                         // // if (orginSource.hasOwnProperty(key)) {
        //                         // //     to[key] = orginSource[key];
        //                         // // }

        //                         // // if (Object.prototype.hasOwnProperty(orginSource, key)) {
        //                         // //     to[key] = orginSource[key];
        //                         // // }
        //                     }


        //                 }
        //             }
        //             return to;
        //         },
        //         writable: true,
        //         configurable: true
        //     });
        // }
        // let targetObj = { p1: "p1", [Symbol("p2")]: "p2" };
        // let sex = Symbol("sex");
        // let obj = {
        //     name: "szq", age: 11, [sex]: "man",
        //     get sex() { return this[sex]; },
        //     set sex(value) { this[sex] = value; },
        //     getName: function () { return this.name; }
        // };
        // obj.prop1 = "prop1";
        // // 1)在使用Object.defineProperty()、Object.defineProperties() 或 Object.create() 函数的情况下添加数据属性，writable、enumerable和configurable默认值为false。
        // // 2)使用对象直接量创建的属性，writable、enumerable和configurable特性默认为true。
        // //         {
        // //     "value": "prop2",
        // //     "writable": false,
        // //     "enumerable": false,
        // //     "configurable": false
        // // }
        // Reflect.defineProperty(obj, "prop2", { value: "prop2" });


        // let resultObj = Object.assign2(targetObj, obj);

        // console.log("obj--getOwnPropertyDescriptors>", Object.getOwnPropertyDescriptors(obj));

        // console.log("resultObj--getOwnPropertyDescriptors>", Object.getOwnPropertyDescriptors(resultObj));

        // //  to[key] = orginSource[key];得到的 prop2 
        //  //         {
        // //     "value": "prop2",
        // //     "writable": true,
        // //     "enumerable": true,
        // //     "configurable": true
        // // }
        // console.log(resultObj);

        //////////////////////////////////////////////////////////////
        //Object.assign 模拟实现(实现原理) class 拷贝； 不能用Object.assign 请参考classMixin.html  
        //////////////////////////////////////////////////////////////


        if (typeof Object.assign2 != 'function') {
            // Attention 1
            Object.defineProperty(Object, "assign2", {
                value: function (target) {
                    'use strict';
                    if (target == null) { // Attention 2
                        throw new TypeError('Cannot convert undefined or null to object');
                    }
                    // Attention 3
                    // Object(value)表示将value转成一个对象，new Object(value)则表示新生成一个对象，它的值是value。
                    let to = Object(target);
                    for (let index = 1; index < arguments.length; index++) {
                        let orginSource = arguments[index];
                        if (orginSource != null) {  // Attention 2
                            // Attention 4                           
                            for (let key of Reflect.ownKeys(orginSource)) {
                                // 真正的拷贝 注意这是第一层自身属性深度拷贝，第二层之后是浅拷贝！
//                                 该方法的引入目的，主要是为了解决Object.assign()无法正确拷贝get属性和set属性的问题。 
//                                 这是因为Object.assign方法总是拷贝一个属性的值，而不会拷贝它背后的赋值方法或取值方法。
// 　　                            Object.getOwnPropertyDescriptors()方法配合Object.defineProperties()方法，就可以实现正确拷贝
                                Reflect.defineProperty(to, key, Reflect.getOwnPropertyDescriptor(orginSource, key));

                            }
                        }
                    }
                    return to;
                },
                writable: true,
                configurable: true
            });
        }

        class A {
            p1 = "p1";
            [Symbol("p2")] = "p2";
            static staticAfun() { return "staticAfun"; }
        };

        let sex = Symbol("sex");

        class B {
            myname = "szq";  // 实例属性
            age = 11;// 实例属性
            [sex] = "man"; // 实例属性
            get sex2() { return this[sex]; } // 原型对象的属性
            set sex2(value) { this[sex] = value; }  // 原型对象的属性
            getName() { return this.name; }  // 原型对象的属性
            static staticBfun() { return "staticBfun"; }  // 静态属性
        };

        

        // console.log(Object.getOwnPropertyDescriptors(b));

        // for (let key of Reflect.ownKeys(B)) { // 这里只有 静态属性 length,name,prototype,staticBfun
        //     console.log(key);
        //     console.log(Reflect.getOwnPropertyDescriptor(b, key));

        // }

        // for (let key of Reflect.ownKeys(B.prototype)) { // 这里只有原型对象的 constructor getName
        //     console.log(key);
        //     console.log(Reflect.getOwnPropertyDescriptor(b, key));

        // }

        // let b = new B();
        //  for (let key of Reflect.ownKeys(b)) { // 这里只有实例属性 myname age  Symbol("sex") 
        //     console.log(key);
        //     console.log(Reflect.getOwnPropertyDescriptor(b, key));

        // }
        
        // B 拷贝到A  **注意这里没有拷贝实例属性
        Object.assign2(A, B); // 静态属性拷贝 B.length,B.name,B.prototype,staticBfun

        let resultObj = Object.assign2(A, B.prototype); // 原型对象的属性拷贝 B.constructor B.getName B.sex2


         resultObj["sex2"]="111";

        // 无法拷贝实例属性
        // ES2017 引入了Object.getOwnPropertyDescriptors() 方法，返回指定对象所有自身属性（不包括非继承属性）的描述对象
        console.log(Object.getOwnPropertyDescriptors(resultObj));


    </script>
</head>

<body>

</body>

</html>